//
//  MSView.swift
//  onemeetingmac
//
//  Created by 张衡 on 2019/12/18.
//  Copyright © 2019 onemeeting. All rights reserved.
//

import Foundation

protocol DestinationViewDelegate {
    func processImageURLs(_ urls: [URL], center: NSPoint) // 图片url
    func processImage(_ image: NSImage, center: NSPoint)  // 图片
}

protocol MouseDelegate {
    func mouseDelegate_mouseDragged(view:NSView, currntPoint: NSPoint)
    func mouseDelegate_mouseDown(view:NSView, event: NSEvent)
    func mouseDelegate_mouseUp(view:NSView, event: NSEvent)
}


class MSView: NSView {
    //自定义tag
    var _tag:Int = 0
    override var tag: Int {
        get {
            return _tag
        }
        set(newValue){
            _tag = newValue
        }
    }
    
    //取消点击
    var isEnable:Bool = true
    
    //模拟状态
    var status:OneStatusBlock?
    
    //单击
    var tap:OneViewBlock?
    var mouseDelegate:MouseDelegate?
    
    //单点和多点
    var onClick:OneTapClick?
    var donbleClick:OneTapClick?
    private var _downbleClickTimer:Timer?
    
    //慢点和快点
    var isImpl:Bool = false
    
    //手势无效
    var isUserInvalid:Bool = false
    
    //拖动手势
    var draggedClick:OneDraggedEvent?
    var hasDrapCursor:Bool = false
    var dragFirst:Bool = true
    var mouseLocBeforeDrag:CGPoint = CGPoint.zero
    
    //拖拽事件
    var dropDelegate:DestinationViewDelegate?
    var isReceivingDrag:Bool = false{
        didSet {
            self.needsDisplay = true
        }
    }
    
    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
        
        let optios:NSTrackingArea.Options = [
            NSTrackingArea.Options.mouseEnteredAndExited,
            NSTrackingArea.Options.mouseMoved,
            NSTrackingArea.Options.cursorUpdate,
            NSTrackingArea.Options.activeWhenFirstResponder,
            NSTrackingArea.Options.activeInKeyWindow,
            NSTrackingArea.Options.activeInActiveApp,
            NSTrackingArea.Options.activeAlways,
            NSTrackingArea.Options.assumeInside,
            NSTrackingArea.Options.inVisibleRect,
            NSTrackingArea.Options.enabledDuringMouseDrag
        ]
        
        let area = NSTrackingArea.init(rect: dirtyRect, options: optios, owner: self, userInfo: nil)
        self.addTrackingArea(area)
        self.becomeFirstResponder()
    }
    
    /*
    override func updateTrackingAreas() {
        let optios:NSTrackingArea.Options = [
                   NSTrackingArea.Options.mouseEnteredAndExited,
                   NSTrackingArea.Options.mouseMoved,
                   NSTrackingArea.Options.cursorUpdate,
                   NSTrackingArea.Options.activeWhenFirstResponder,
                   NSTrackingArea.Options.activeInKeyWindow,
                   NSTrackingArea.Options.activeInActiveApp,
                   NSTrackingArea.Options.activeAlways,
                   NSTrackingArea.Options.assumeInside,
                   NSTrackingArea.Options.inVisibleRect,
                   NSTrackingArea.Options.enabledDuringMouseDrag
               ]
               
        let area = NSTrackingArea.init(rect: self.bounds, options: optios, owner: self, userInfo: nil)
        self.addTrackingArea(area)
        self.becomeFirstResponder()
    }
    */
    
    

    override func mouseDown(with event: NSEvent) {
        if self.isEnable == false {
            return
        }
        
        super.mouseDown(with: event)
        
        if self.isUserInvalid  {
            return
        }
        
        if self.status != nil {
            self.status!(.selected)
        }
        
        if self.mouseDelegate != nil {
            self.mouseDelegate?.mouseDelegate_mouseDown(view: self, event: event)
        }
        
        if event.clickCount > 1 {
            self._downbleClickTimer?.invalidate()
            self.onDoubleClick(theEvent: event)
        }else if event.clickCount == 1 {
            // NSEvent.doubleClickInterval() - too long
            self._downbleClickTimer = Timer.scheduledTimer(timeInterval: 0.3,
                                                      target: self,
                                                      selector: #selector(onDoubleClickTimeout(timer:)),
                                                      userInfo: event,
                                                      repeats: false)
        }
        

       if self.tap != nil {
           self.tap!(self)
       }
        
        if self.isImpl == true {
            
            while true {
                guard let nextEvent = self.window?.nextEvent(matching: [.leftMouseUp, .leftMouseDragged]) else { continue }
                let mouseLocation = self.convert(nextEvent.locationInWindow, from: nil)
                let isInside = self.bounds.contains(mouseLocation)

                switch nextEvent.type {
                case .leftMouseDragged:
                     if isInside {
                         mouseDraggedImpl(with: nextEvent)
                     }
                case .leftMouseUp:
                     mouseUpImpl(with: nextEvent)
                     return

                default:
                    break
                }
            }
        }
        
    }
    
    
    
    func mouseDownImpl(with event: NSEvent) {
        
        /*
        for _ in 0..<4 {
            let downEvent = event.cgEvent
            downEvent?.setIntegerValueField(CGEventField.init(rawValue: 404)!, value: 2)
            downEvent?.type = .leftMouseDown
            downEvent?.post(tap: CGEventTapLocation.cghidEventTap)
            downEvent?.type = .leftMouseDown
            downEvent?.post(tap: CGEventTapLocation.cghidEventTap)
        }
        */
        
        //print("mouseDown")
    }
    
    func mouseDraggedImpl(with event: NSEvent) {
        
        //print("mouseDragged")
    }
    
    func mouseUpImpl(with event: NSEvent) {
        //print("mouseUp")
    }
    
    override func mouseUp(with event: NSEvent) {
        if self.isEnable == false {
            return
        }
        super.mouseUp(with: event)
        
        self.dragFirst = true
        
        if self.status != nil {
            self.status!(.highlight)
        }
        
        if self.mouseDelegate != nil {
            self.mouseDelegate?.mouseDelegate_mouseUp(view: self, event: event)
        }
        
    }
    
    override func mouseEntered(with event: NSEvent) {
        if self.isEnable == false {
            return
        }
        
        super.mouseEntered(with: event)
        if self.status != nil {
            self.status!(.hover)
        }
    }
    
    override func mouseExited(with event: NSEvent) {
        if self.isEnable == false {
            return
        }
        
        super.mouseExited(with: event)
        if self.status != nil {
            self.status!(.normal)
        }
    }
    
    /*
    override var acceptsFirstResponder: Bool {
        return true
    }
    */
    

    @objc func onDoubleClickTimeout(timer: Timer) {
        self.onClick(theEvent: timer.userInfo as! NSEvent)
    }

    func onClick(theEvent: NSEvent) {
        if self.onClick != nil {
            self.onClick!(self,theEvent)
        }
    }

    func onDoubleClick(theEvent: NSEvent) {
        if self.donbleClick != nil {
            self.donbleClick!(self,theEvent)
        }
    }
    
    override func mouseMoved(with event: NSEvent) {
        /*
        let point = event.locationInWindow
        let dx = point.x
        let dy = point.y
        if self.hasDrap {
            //self.moveMouse(dx, dy)
            //NSCursor.crosshair.set()
            if dragFirst == true {
                self.dragFirst = false
                var mouseLoc = NSEvent.mouseLocation
                mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLocBeforeDrag.y
                print("moving \(mouseLoc.x) \(mouseLoc.y)")
                //let newLoc =  CGPoint(x: mouseLoc.x-CGFloat(dx), y: mouseLoc.y+CGFloat(dy))
                //CGDisplayMoveCursorToPoint(0, newLoc)
            }
            mouse_event_to(button: CGMouseButton.left,type: .leftMouseDragged, x: mouseLocBeforeDrag.x-dx, y: mouseLocBeforeDrag.y+dy)
        }
        */
    }
    
   
    
    
    func moveMouse(_ dx:CGFloat , _ dy:CGFloat){
        //先监控移动前鼠标位置
        var mouseLoc = NSEvent.mouseLocation
        mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLoc.y;
        //计算鼠标新位置
        let newLoc = CGPoint(x: mouseLoc.x-CGFloat(dx), y: mouseLoc.y+CGFloat(dy))
        print("moving \(dx) \(dy)")
        CGDisplayMoveCursorToPoint(0, newLoc)
        
    }
    
    func mouse_event_to(button:CGMouseButton,type:CGEventType,x:CGFloat,y:CGFloat) {
        guard let moveEvent = CGEvent(mouseEventSource: nil,
                                      mouseType: type,
                                      mouseCursorPosition: CGPoint.init(x: x, y: y),
                                      mouseButton: .left) else {return}
        moveEvent.post(tap: .cghidEventTap)
    }
    
    override func mouseDragged(with event: NSEvent) {
        if self.isEnable == false {
            return
        }
        
        super.mouseDragged(with: event)
        
        if self.hasDrapCursor {
            NSCursor.resizeLeftRight.set()
        }
        
        let location = event.locationInWindow
        if self.mouseDelegate != nil {
            self.mouseDelegate?.mouseDelegate_mouseDragged(view: self, currntPoint: location)
        }
        if self.draggedClick != nil {
            self.draggedClick!(self,event)
        }
    }
    
    override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
        if self.isEnable == false {
            return false
        }
        self.isReceivingDrag = false
        let pasteBoard = sender.draggingPasteboard
        let point = convert(sender.draggingLocation, from: nil)
        let filteringOptions = [NSPasteboard.ReadingOptionKey.urlReadingContentsConformToTypes:NSImage.imageTypes]
        if let urls = pasteBoard.readObjects(forClasses: [NSURL.self], options: filteringOptions) as? [URL], urls.count > 0 {
            //在DestinationView中自定的协议DestinationViewDelegate传送数据
            self.dropDelegate?.processImageURLs(urls, center: point)
            return true
        }
            
        return false
    }
    
    override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation {
        return NSDragOperation()
    }
    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        if self.isEnable == false {
            return NSDragOperation()
        }
        let allow = shouldAllowDrag(sender)
        self.isReceivingDrag = allow
        return allow ? .copy : NSDragOperation()
    }
    
    override func draggingExited(_ sender: NSDraggingInfo?) {
        if self.isEnable == false {
            return
        }
        self.isReceivingDrag = false
    }
    
    
}

extension MSView {
    
    func shouldAllowDrag(_ draggingInfo: NSDraggingInfo) -> Bool {
        var canAccept = false
        //2.从拖拽session信息中获取对拖拽粘贴板的引用
        let pasteBoard = draggingInfo.draggingPasteboard
        //3.询问粘贴板它是否包含任何的URL，以及这些URL是指向图片的。如果有图片的话，就接受这个拖拽。否则，拒绝它
        let filteringOptions = [NSPasteboard.ReadingOptionKey.urlReadingContentsConformToTypes:NSImage.imageTypes]
        if pasteBoard.canReadObject(forClasses: [NSURL.self], options: filteringOptions) {
            canAccept = true
        }
        return canAccept
    }
}
